package tools

import (
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"fmt"
	"github.com/go-pay/gopay"
	"github.com/go-pay/util"
	"github.com/go-pay/util/convert"
	"time"
)

// "appid": "wx881636f222fbeb35",  // 微信开放平台 - 应用 - AppId，注意和微信小程序、公众号 AppId 可能不一致
// "noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
// "package": "Sign=WXPay",        // 固定值
// "partnerid": "148*****52",      // 微信支付商户号
// "prepayid": res.data.data.PrepayId, // 统一下单订单号
// "timestamp": new Date().getTime()/1000,        // 时间戳（单位：秒）
// "sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名，这里用的 MD5/RSA 签名
type WeixinSmallInfo struct {
	Provider   string `json:"provider"`
	TimeStamp  string `json:"timeStamp"`
	NonceStr   string `json:"nonceStr"`
	Package    string `json:"package"`
	SignType   string `json:"signType"`
	PaySign    string `json:"paySign"`
	OutTradeNo string `json:"outTradeNo"`
}

type WeixinAppInfo struct {
	Appid     string `json:"appid"`
	Partnerid string `json:"partnerid"`
	Prepayid  string `json:"prepayid"`
	Package   string `json:"package"`
	Noncestr  string `json:"noncestr"`
	Timestamp string `json:"timestamp"`
	Sign      string `json:"sign"`
}

func rsaSign(str string, privateKey *rsa.PrivateKey) (string, error) {
	if privateKey == nil {
		return "", errors.New("privateKey can't be nil")
	}
	h := sha256.New()
	h.Write([]byte(str))
	result, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, h.Sum(nil))
	if err != nil {
		return gopay.NULL, fmt.Errorf("[%w]: %+v", gopay.SignatureErr, err)
	}
	return base64.StdEncoding.EncodeToString(result), nil
}

// PaySignOfApp 获取 App 支付所需要的参数
// 文档：https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/app-transfer-payment.html
func PaySignOfApp(appid, mchid, prepayid string, privateKey *rsa.PrivateKey) (app *WeixinAppInfo, err error) {
	ts := convert.Int642String(time.Now().Unix())
	nonceStr := util.RandomString(32)

	_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + prepayid + "\n"
	sign, err := rsaSign(_str, privateKey)
	if err != nil {
		return nil, err
	}

	app = &WeixinAppInfo{
		Appid:     appid,
		Partnerid: mchid,
		Prepayid:  prepayid,
		Package:   "Sign=WXPay",
		Noncestr:  nonceStr,
		Timestamp: ts,
		Sign:      sign,
	}
	return app, nil
}

// PaySignOfJSAPI 获取 JSAPI 支付所需要的参数
// 文档：https://pay.weixin.qq.com/docs/merchant/apis/jsapi-payment/jsapi-transfer-payment.html
func PaySignOfJSAPI(appid, prepayid string, OutTradeNo string, privateKey *rsa.PrivateKey) (jsapi *WeixinSmallInfo, err error) {
	ts := convert.Int642String(time.Now().Unix())
	nonceStr := util.RandomString(32)
	pkg := "prepay_id=" + prepayid

	_str := appid + "\n" + ts + "\n" + nonceStr + "\n" + pkg + "\n"
	sign, err := rsaSign(_str, privateKey)
	if err != nil {
		return nil, err
	}

	jsapi = &WeixinSmallInfo{
		Provider:   "wxpay",
		TimeStamp:  ts,
		NonceStr:   nonceStr,
		Package:    pkg,
		SignType:   "RSA",
		PaySign:    sign,
		OutTradeNo: OutTradeNo,
	}
	return jsapi, nil
}

/**
* 调起微信支付--小程序
* @param prepayId 预支付交易会话ID
 */
func SmallAppOrderInfo(prepayId string, OutTradeNo string, privateKey *rsa.PrivateKey) *WeixinSmallInfo {
	jsapi, _ := PaySignOfJSAPI("wx2130f87b8f96cff7", prepayId, OutTradeNo, privateKey)
	return jsapi
}

/**
* 调起微信支付--app
* @param prepayId 预支付交易会话ID
 */
func AppOrderInfo(prepayId string, privateKey *rsa.PrivateKey) *WeixinAppInfo {
	jsapi, _ := PaySignOfApp("wx881636f222fbeb35", "1615158475", prepayId, privateKey)
	return jsapi
}
